#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import sys
import os
import ctypes
from ctypes.wintypes import *
from PyQt4.QtCore import *
from PyQt4.QtGui import *

'''
Copyright (C) 2009-2010 dbzhang800@gmail.com
All rights reserved.
''' 

GENERIC_READ = (-2147483648)
FILE_SHARE_READ = 1
OPEN_EXISTING = 3
INVALID_HANDLE_VALUE = -1
NULL = 0
IOCTL_EZUSB_BULK_READ = 0x0022204E
REALTIME_PRIORITY_CLASS = 0x00000100

kernel32 = ctypes.windll.kernel32
CreateFile = kernel32.CreateFileW
CloseHandle = kernel32.CloseHandle
DeviceIoControl = kernel32.DeviceIoControl
SetPriorityClass = kernel32.SetPriorityClass
GetCurrentProcess = kernel32.GetCurrentProcess

class BULK_TRANSFER_CONTROL(ctypes.Structure):
    _fields_ = [("pipeNum", ULONG),]

class Ezusb(QThread):
    imageReady = pyqtSignal(QPixmap)
    def __init__(self, handle, parent=None):
        super(Ezusb, self).__init__(parent)
        self._stop = False
        self.handle = handle
        self.image = QImage(512,  512,  QImage.Format_Indexed8)
        self.colorTable = [qRgb(i, i, i) for i in range(256)]
        self.image.setColorTable(self.colorTable)

    def stop(self):
        self._stop = True
        
    def run(self):
        self.setPriority(QThread.TimeCriticalPriority)
        self._stop = False
        bulkControl = BULK_TRANSFER_CONTROL(pipeNum=1)
        buff = ctypes.create_string_buffer(512*16)
        bytesReturned = DWORD()
        lenth = buff._length_
        while (not self._stop):
            res = DeviceIoControl(self.handle,
                    IOCTL_EZUSB_BULK_READ,
                    ctypes.byref(bulkControl),
                    ctypes.sizeof(BULK_TRANSFER_CONTROL),
                    buff,
                    lenth,
                    ctypes.byref(bytesReturned),
                    NULL
                    )
            if res:
                row = (ord(buff[511])<<8)+ord(buff[510])
                if row + 16 == 511:
                    ctypes.memmove(int(self.image.bits())+512*row,  buff,  bytesReturned.value)
                    self.imageReady.emit(QPixmap.fromImage(self.image))
                elif row + 16 > 511:
                    ctypes.memmove(int(self.image.bits())+512*row,  buff, (511-row)*512)
                    self.imageReady.emit(QPixmap.fromImage(self.image))
                    ctypes.memmove(int(self.image.bits()),  ctypes.byref(buff, (511-row)*512), (row+16-511)*512)
                else:
                    ctypes.memmove(int(self.image.bits())+512*row,  buff,  bytesReturned.value)


class View(QWidget):
    def __init__(self, parent=None):
        super(View, self).__init__(parent)
        self.initUi()
        self.handle = self.openEzusb()
        self.thread = Ezusb(self.handle)
        
        self.startButton.clicked.connect(self.thread.start)
        self.stopButton.clicked.connect(self.thread.stop)
        self.thread.imageReady.connect(self.viewLabel.setPixmap)
        
    def initUi(self):
        self.viewLabel = QLabel(self)
        self.viewLabel.setMinimumSize(QSize(512, 512))
        self.startButton = QPushButton("Start",  self)
        self.stopButton = QPushButton("Stop",  self)
        vbox = QVBoxLayout(self)
        vbox.addWidget(self.viewLabel)
        vbox.addStretch()
        hline = QFrame(self)
        hline = QFrame(self)
        hline.setFrameShape(QFrame.HLine)
        hline.setFrameShadow(QFrame.Sunken)
        vbox.addWidget(hline)
        hbox = QHBoxLayout()
        hbox.addStretch()
        hbox.addWidget(self.stopButton)
        hbox.addWidget(self.startButton)
        vbox.addLayout(hbox)
        self.setLayout(vbox)
        self.setWindowTitle("HMI Ezusb")
             
    def closeEvent(self,  e):
        if self.thread.isRunning:
            self.thread.stop()
            self.thread.wait(200)
        if self.handle != INVALID_HANDLE_VALUE:
            CloseHandle(self.handle)
        
    def openEzusb(self):
        handle = CreateFile(
                ur'\\.\ezusb-0',
                GENERIC_READ, 
                FILE_SHARE_READ, 
                NULL, 
                OPEN_EXISTING, 
                0, 
                NULL) 
        if handle == INVALID_HANDLE_VALUE:
            print ctypes.FormatError() 
            exit(1)
        return handle
    

        
def main():
    app = QApplication(sys.argv)
    SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS)
    w = View()
    w.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

